import {AxdrType} from "./AxdrType";
import {Buffer} from "buffer";
import {AxdrLength} from "./AxdrLength";
import {ReverseByteArrayOutputStream} from "../ReverseByteArrayOutputStream";
import {ReverseByteArrayInputStream} from "../ReverseByteArrayInputStream";

export class AxdrBitString implements AxdrType{

    bitString : Buffer | null = null;
    numBits : number = 0;
    fixedLength : boolean = false;

    constructor() {

    }

    setNumBit(numBits : number){
        this.numBits = numBits;
        this.fixedLength = true;
    }

    setBitString(value : Buffer){
        this.bitString = value;
        this.fixedLength = true;
    }

    encode(output: ReverseByteArrayOutputStream): number {
        if(this.bitString == null){
            throw new Error("bitString is null");
        }else{
            let codeLength = this.bitString.length;
            for(let i = this.bitString.length - 1; i >= 0; --i){
                output.write(this.bitString[i]);
            }
            if (!this.fixedLength) {
                let length = new AxdrLength(this.numBits);
                codeLength += length.encode(output);
            }
            return codeLength;
        }
    }

    decode(input: ReverseByteArrayInputStream): number {
        let codeLength = 0;
        if (!this.fixedLength) {
            let l = new AxdrLength(0);
            codeLength += l.decode(input);
            this.numBits = l.getValue();
        }
        let byteArrayLength = this.numBits % 8 == 0 ? this.numBits / 8 : this.numBits / 8 + 1;
        codeLength += byteArrayLength;
        this.bitString = Buffer.alloc(byteArrayLength);
        if (byteArrayLength != 0 && input.readoffset(this.bitString, 0, byteArrayLength) < byteArrayLength) {
            throw new Error("Error Decoding AxdrBitString");
        }
        return codeLength;
    }

    getValue() : Buffer{
        if(this.bitString == null){
            throw new Error("bitString is null");
        }else{
            return this.bitString;
        }
    }

    getNumBits() : number{
        return this.numBits;
    }

    toString() : string{
        if(this.bitString == null){
            return "bitString is null";
        }else{
            let s = "";
            for(let i = 0; i < this.numBits; i++){
                if(((this.bitString[i / 8] & 0xff) & (0x80 >> (i % 8))) == (0x80 >> (i % 8))){
                    s.concat('1');
                }else{
                    s.concat('0');
                }
            }
            return s.toString();
        }
    }

}
